package com.excesys.exsecs.access.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.excesys.exsecs.access.constant.RedisConstant;
import com.excesys.exsecs.access.constant.enums.AccessThingModelEnum;
import com.excesys.exsecs.access.entity.AccessDeviceInfo;
import com.excesys.exsecs.access.entity.AccessThingModel;
import com.excesys.exsecs.access.entity.DataFlowOperation;
import com.excesys.exsecs.access.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class ProtocolTransitionServiceImpl implements ProtocolTransitionService {

	private final StringRedisTemplate redisTemplate;
	private final AccessDeviceInfoService accessDeviceInfoService;
	private final AccessThingModelService accessThingModelService;
	private final DataFlowOperationService dataFlowOperationService;
	//private final MqttConfig.MqttProducer mqttProducer;

	@Override
	public void ayncDeal(JSONObject payloadJson) {
		try {
			String unitNo = payloadJson.getStr(RedisConstant.UNIT_NO);
			Long timestamp = payloadJson.getLong(RedisConstant.TIMESTAMP);
			Integer online = payloadJson.getInt(RedisConstant.ONLINE);
			JSONObject dataJson = payloadJson.getJSONObject(RedisConstant.DATA);
			AccessDeviceInfo device = accessDeviceInfoService.getOne(Wrappers.<AccessDeviceInfo>lambdaQuery().eq(AccessDeviceInfo::getUnitNo, unitNo));
			if (ObjectUtils.isEmpty(device)){
				return;
			}
			//在线状态处理。
			if (!device.getOnlineStatus().equals(online)){
				device.setOnlineStatus(online);
				device.setUpdateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()));
				accessDeviceInfoService.updateById(device);
			}
			// 1.原始数据存入redis中
			redisTemplate.opsForHash().put(RedisConstant.REPORT_LIST_KEY, unitNo, payloadJson.toString());
			//2.物模型添加实时数据
			AccessThingModel thing = accessThingModelService.getOne(Wrappers.<AccessThingModel>lambdaQuery().eq(AccessThingModel::getProductKey, device.getProductKey()));
			//如果该设备对应的产品没有物模型及物模型中的properties，则return
			if (ObjectUtils.isEmpty(thing)){
				return;
			}
			JSONObject model = thing.getModel();
			List<JSONObject> properties = model.getBeanList(AccessThingModelEnum.PROPERTIES.getCode(), JSONObject.class);
			if (CollectionUtils.isEmpty(properties)){
				return;
			}
			if (CollectionUtils.isNotEmpty(dataJson)){
				properties.stream().forEach(prop ->{
					prop.set(RedisConstant.VALUE, dataJson.getObj(prop.getStr(RedisConstant.IDENTIFIER)));
					prop.set(RedisConstant.TIMESTAMP, timestamp);
				});
			}
			redisTemplate.opsForHash().put(RedisConstant.PROPERTIES_LIST_KEY, unitNo, properties.toString());

			//3、录入流水表
			String tableName = "t_" + unitNo;
			int count = dataFlowOperationService.checkTableExists("exsecsx_link", tableName);
			if (count != 0){
				DataFlowOperation dataFlow = new DataFlowOperation(tableName, unitNo, JSONUtil.toJsonStr(dataJson), LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()));
				dataFlowOperationService.executeInsertSql(dataFlow);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 设备离线处理
	 * @param payloadJson
	 */
	@Override
	public void offlineDeal(JSONObject payloadJson) {
		String unitNo = payloadJson.getStr(RedisConstant.UNIT_NO);
		Long timestamp = payloadJson.getLong(RedisConstant.TIMESTAMP);
		Integer online = payloadJson.getInt(RedisConstant.ONLINE);
		// 1、更新redis实时报文
		Object redisObj = redisTemplate.opsForHash().get(RedisConstant.REPORT_LIST_KEY, unitNo);
		if (ObjectUtils.isNotEmpty(redisObj)){
			JSONObject redisPayloadJson = JSONUtil.parseObj(redisObj);
			redisPayloadJson.put(RedisConstant.ONLINE, online);
			redisTemplate.opsForHash().put(RedisConstant.REPORT_LIST_KEY, unitNo, redisPayloadJson.toString());
		} else {
			redisTemplate.opsForHash().put(RedisConstant.REPORT_LIST_KEY, unitNo, payloadJson.toString());
		}
		// 2、更新设备表的在线状态
		AccessDeviceInfo device = accessDeviceInfoService.getOne(Wrappers.<AccessDeviceInfo>lambdaQuery().eq(AccessDeviceInfo::getUnitNo, unitNo));
		if (ObjectUtils.isEmpty(device)){
			return;
		}
		if (!device.getOnlineStatus().equals(online)){
			device.setOnlineStatus(online);
			accessDeviceInfoService.updateById(device);
		}
	}
}
